﻿using System;
using System.Linq;
using System.Collections.Generic;
using RayDen.RayEngine;

namespace PathEngine
{
    public class RayProcessor
    {
        private IRayTracingDevice rtDevice;
        private FrameDataset dataSet;

        public RayProcessor(FrameDataset sceneInfo, IRayTracingDevice rtDev)
        {
            rtDevice = rtDev;
            dataSet = sceneInfo;
        }

        public TriangleMesh GetMesh(uint primitiveId)
        {
            return dataSet.Shapes[primitiveId];
        }


        public void Process(RayCollection rayBuffer)
        {

            var topLevelHits = new SortedDictionary<uint, List<Tuple<Ray, PrimitiveHit>>>();
            rtDevice.TraceBuffer(rayBuffer);
            for (int index = 0; index < rayBuffer.rayHits.Length; index++)
            {
                if (!topLevelHits.ContainsKey(rayBuffer.rayHits[index].PrimitiveId))
                {
                    topLevelHits.Add(rayBuffer.rayHits[index].PrimitiveId, new List<Tuple<Ray, PrimitiveHit>>());
                }
                topLevelHits[rayBuffer.rayHits[index].PrimitiveId].Add(new Tuple<Ray, PrimitiveHit>(rayBuffer.RaysInfo[index], rayBuffer.rayHits[index]));
            }
            //Process Top Level Hits

            foreach (var topLevelHit in topLevelHits)
            {
                var prim = GetMesh(topLevelHit.Key);
                var rays = topLevelHit.Value.Select(item => item.Item1).ToArray();

                var buffer = new RayCollection(rays.Length);

                rtDevice.SetData(prim.BottomLevelBVH);
                rtDevice.TraceBuffer(buffer);
                for (int index = 0; index < buffer.rayHits.Length; index++)
                {
                    rayBuffer.UpdateHit(buffer.RaysInfo[index].Id, ref buffer.rayHits[index]);
                }
            }

        }

    }
}